﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using devtm.Aop.Event;
using System.Reflection;
using System.Diagnostics;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using Mono.Cecil;
using ICSharpCode.Decompiler.ILAst;
using devtm.Aop.Extensions;
using System.IO;
using ICSharpCode.NRefactory.CSharp;

namespace devtm.Aop.Behavior
{

    [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)]
    public abstract class InterceptExceptionAttribute : InterceptAttribute, devtm.Aop.Event.IInterceptInterceptException
    {


        public InterceptExceptionAttribute()
        {

        }


        [DebuggerStepThrough]
        [InterceptEventAttribute(InterceptEnumEventType.Catch)]
        public virtual void OnException(object sender, InterceptEventArgs args, int context)
        {
            try
            {
                args.Context = context;
                CatchException(sender, args);
            }
            catch (Exception e)
            {

                if (e.Data.Contains("CodeStart"))
                    throw;

                InterceptAttribute.Error(args, e);

            }

        }
       

        [DebuggerStepThrough]
        [InterceptEventAttribute(InterceptEnumEventType.AfterCall)]
        public virtual void OnFinally(object sender, InterceptEventArgs args, int context)
        {
            try
            {
                args.Context = context;
                if (args.Exception != null)
                    Finally(sender, args);
            }
            catch (Exception e)
            {
                InterceptAttribute.Error(args, e);
            }
            
        }
        

        protected string GetCode(InterceptEventArgs args, bool html, out int start, out int end, out int line)
        {
            return InterceptEventArgsHelper.GetCode(args, html, out start, out end, out line);
        }


        /// <summary>
        /// Wraps the exception.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="args">The <see cref="devtm.Aop.Event.InterceptEventArgs"/> instance containing the event data.</param>
        /// <returns></returns>
        protected T WrapException<T>(InterceptEventArgs args, bool html)
            where T : Exception
        {            

            int start = 0;
            int end = 0;
            int line = 0;

            string message;

            string code = GetCode(args, html, out start, out end, out line);

            if (html)

                message = @"<div class=""error"">"
                        + args.Exception.Message
                        + "</div>"
                        + @"<div class=""stack"">"
                        + code
                        + "</div>";

            else
            {

                message = args.Exception.Message;

                if (message.EndsWith("."))
                    message = message.Substring(0, message.Length - 1);

                message += " at line " 
                    + line.ToString() 
                    + "\n\n\n // --- Code ---\n" 
                    + code 
                    + "\n // --- Code ---\n";

                message += "\n\n\n // --- Stack ---\n";

                message += args.SerializeStack();

                message += "\n // --- Stack ---\n";
            }



            T e = Activator.CreateInstance(typeof(T), new Object[] { message, args.Exception }) as T;
            
            e.Data.Add("CodeStart", start);
            e.Data.Add("CodeEnd", end);
            e.Data.Add("CodeLine", line);
            e.Data.Add("CodeParameters", args.Properties);

            if (html)
                e.Data.Add("CodeStyle", ".stack { font: normal } .simpleType { color: #2BA3D5; } .inLine { border-style: solid; background-color: #FFFF00; border-width: 1px; } .keyWord { color: #0063FF; } .text { color: #C11515; } .comment { color: #8D9600; }");
            
            return e;

        }


        public abstract void CatchException(object sender, InterceptEventArgs args);

        public abstract void Finally(object sender, InterceptEventArgs args);
        

    }


}
